﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.OMM.Util;
using Sinacor.OMM.HealthMonitor.Collector.SharedHealthDataMemoryStorage.OrderExecutor;
using Sinacor.OMM.HealthMonitor.Collector;
using System.Diagnostics;
using PSE.Framework.Threading;

namespace Sinacor.OMM.OrderExecutor.ProcessLogic
{
    public class BusinessExecutor
    {

        #region Properties

        private OMM.OrderExecutor.ResourceAccess.BusinessExecutor _resourceAccess;
        private Util.TraceWriter _traceWriter;
        private bool running;
        private OrderExecutorShdms _orderExecutorStatus;
        private Sinacor.OMM.HealthMonitor.Entity.Common.ErrorData _errorData;
        Stopwatch _procedureTimer;
        DateTime _day;
        long _numberOfProcedureExecutionWithErrors;
        DateTime _nextschedule;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public BusinessExecutor()
        { }

        #endregion

        #region Methods

        /// <summary>
        /// Run
        /// </summary>
        public void Run()
        {
            _resourceAccess = new Sinacor.OMM.OrderExecutor.ResourceAccess.BusinessExecutor(OrderExecutorConfigurationManager.CompanyId);
            _traceWriter = Tracer.GetInstance("OrderExecutor", "BusinessExecutorLog");
            _orderExecutorStatus = OrderExecutorShdms.GetSharedStorage();
            _procedureTimer = new Stopwatch();

            _traceWriter.Trace("Business executor has been started.");
            running = true;
            InitializeExecution();
        }

        /// <summary>
        /// Stop
        /// </summary>
        public void Stop()
        {
            running = false;

            if (_resourceAccess != null)
                _resourceAccess = null;

            _procedureTimer = null;
            Tracer.Destroy();
        }


        private void InitializeExecution()
        {
            _traceWriter.Trace("Begin InitializeExecution", TraceType.Optional);
            int recCont = 0;
            while (running)
            {
                try
                {
                    _errorData = new Sinacor.OMM.HealthMonitor.Entity.Common.ErrorData();

                    _traceWriter.Trace("Stored procedure PR_NEGOCIOS.NEGAUT380_Proc will be executed", TraceType.Optional);
                    _procedureTimer.Start();
                    recCont = _resourceAccess.ExecuteProcessBusiness();
                    _procedureTimer.Stop();
                    _traceWriter.Trace("Stored procedure PR_NEGOCIOS.NEGAUT380_Proc executed sucessfuly.", TraceType.Optional);

                    _errorData.Reset();
                    _numberOfProcedureExecutionWithErrors = 0;
                    if (recCont.Equals(0))
                        Sleeper.Sleep(OrderExecutorConfigurationManager.RefreshTimer, IsRunning);
                }
                catch (System.Data.Common.DbException dbEx)
                {
                    _traceWriter.Trace(String.Concat("Error when trying to execute stored procedure PR_NEGOCIOS.NEGAUT380_Proc: ", dbEx.Message, dbEx.StackTrace));
                    
                    _errorData = new Sinacor.OMM.HealthMonitor.Entity.Common.ErrorData();
                    _errorData.ExceptionMessage = "Error when trying to execute stored procedure PR_NEGOCIOS.NEGAUT380_Proc: " + dbEx.Message;
                    _errorData.ErrorDescription = dbEx.StackTrace;
                    _orderExecutorStatus.OrderExecutorDataInfo.BusinessExecutor.ErrorData = _errorData;

                    _numberOfProcedureExecutionWithErrors++;
                    _procedureTimer.Stop();
                    Sleeper.Sleep(60000, IsRunning);
                }
                catch (Exception ex)
                {
                    _traceWriter.Trace(String.Concat("Error when trying to execute stored procedure PR_NEGOCIOS.NEGAUT380_Proc: ", ex.Message, ex.StackTrace));

                    _errorData = new Sinacor.OMM.HealthMonitor.Entity.Common.ErrorData();
                    _errorData.ExceptionMessage = "Error when trying to execute stored procedure PR_NEGOCIOS.NEGAUT380_Proc: " + ex.Message;
                    _errorData.ErrorDescription = ex.StackTrace;
                    _orderExecutorStatus.OrderExecutorDataInfo.BusinessExecutor.ErrorData = _errorData;

                    _numberOfProcedureExecutionWithErrors++;
                    _procedureTimer.Stop();
                    Sleeper.Sleep(60000, IsRunning);
                }
                _nextschedule = DateTime.Now.AddMilliseconds(OrderExecutorConfigurationManager.RefreshTimer);
                Collect();

            }
        }

        private bool IsRunning()
        {
            return running;
        }

        /// <summary>
        /// Collect
        /// </summary>
        /// <returns></returns>
        private void Collect()
        {
            _orderExecutorStatus.OrderExecutorDataInfo.BusinessExecutor.LimitProcedureExecutionTime = 5000;
            _orderExecutorStatus.OrderExecutorDataInfo.BusinessExecutor.NextScheduleProcedure = _nextschedule.TimeOfDay.ToString();
            _orderExecutorStatus.OrderExecutorDataInfo.BusinessExecutor.NumberOfExceptionsDataBase = _numberOfProcedureExecutionWithErrors;
            _orderExecutorStatus.OrderExecutorDataInfo.BusinessExecutor.ProcedureExecutionTime = _procedureTimer.ElapsedMilliseconds;
            _procedureTimer.Reset();

            if (_day.Day != DateTime.Now.Day)
            {
                _numberOfProcedureExecutionWithErrors = 0;
                _day = DateTime.Now;
            }
        }

        #endregion

    }
}
